﻿using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TaskManageDemo.Data.Entitys;

namespace TaskManageDemo.Core
{
   public class JobHelp
    {
        /// <summary>
        /// 作业的分组管理名称
        /// </summary>
        public static readonly string jobGroupName = "JOBGROUP";

        /// <summary>
        /// 作业名称 统一作业id-作业名称-作业路径
        /// </summary>
        public static readonly string jobKey = "job-{0}-{1}-{2}";

        /// <summary>
        /// 触发器名称 统一作业id-作业名称-作业路径
        /// </summary>
        public static readonly string triggerKey = "trigger-{0}-{1}-{2}";

        public static JobKey GetJobKey(ScheduleTask task)
        {
            return new JobKey(string.Format(jobKey, task.Id.ToString(), task.TaskName, task.ClassName), jobGroupName);
        }

        public static TriggerKey GetTriggerKey(ScheduleTask task)
        {
            return new TriggerKey(string.Format(triggerKey, task.Id.ToString(), task.TaskName, task.ClassName));
        }

        /// <summary>
        /// 使用作业计划来创建作业
        /// </summary>
        /// <param name="quartzScheduler">调度器</param>
        /// <param name="task">作业任务</param>
        /// <returns>二元组</returns>
        public static Tuple<IJobDetail, ITrigger> CreatScheduleJob(IScheduler quartzScheduler, ScheduleTask task)
        {
            Tuple<IJobDetail, ITrigger> tuple = null;
            IJobDetail ij = CreateJobDetail(task);
            ITrigger it = CreateTrigger(task);

            quartzScheduler.ScheduleJob(ij, it);
            tuple = new Tuple<IJobDetail, ITrigger>(ij, it);

            return tuple;
        }

        /// <summary>
        /// 根据作业计划来创建作业明细
        /// </summary>
        /// <param name="task"></param>
        /// <param name="taskData"></param>
        /// <returns></returns>
        public static IJobDetail CreateJobDetail(ScheduleTask task, IDictionary<string, object> taskData = null)
        {
            if (task == null) throw new ArgumentNullException("『CreateJobDetail』的task参数为空！");
            //反射加载程序集
            var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, string.Format("bin\\TaskManageDemo.Task.dll"));
            Assembly asmb = Assembly.LoadFrom(path);
            Type taskType = asmb.GetType(string.Format("TaskManageDemo.Task.{0}", task.ClassName)); 
            if (taskType == null)
                throw new NotImplementedException(string.Format("『{0}』调用的类型未实现", task.ClassName));

            //作业执行上下文携带数据
            IDictionary<string, object> map = new Dictionary<string, object>() { { "task", task } };
           
            IJobDetail job =
                 JobBuilder.Create(taskType)
                .WithDescription(task.Remark)
                .WithIdentity(GetJobKey(task))
                .UsingJobData(new JobDataMap(map)) 
                .Build();

            return job;
        }

        /// <summary>
        /// 根据作业计划来创建作业触发器
        /// </summary>
        /// <param name="task"></param>
        /// <param name="forJob"></param>
        /// <returns></returns>
        public static ITrigger CreateTrigger(ScheduleTask task, IJobDetail forJob = null)
        {
            if (task == null) throw new ArgumentNullException("『CreateTrigger』的task参数为空！");

            TriggerBuilder trigger = TriggerBuilder.Create();
            trigger.WithDescription(task.Remark)
             .WithIdentity(GetTriggerKey(task));

            trigger = string.IsNullOrEmpty(task.CronExpression) ?
                trigger.WithSimpleSchedule(x => x.WithIntervalInMinutes(30).WithRepeatCount(10)) :
                trigger.WithCronSchedule(task.CronExpression);

            if (forJob != null) trigger.ForJob(forJob);

            return trigger.Build();

        }

        /// <summary>
        /// 当作业计划各属性发生改变时，需要重新启动此作业
        /// </summary>
        /// <param name="qtzScheduler">调度器</param>
        /// <param name="plOld">旧的作业计划</param>
        /// <param name="plNew">新作业计划</param>
        /// <param name="clMethod">采集方法</param>
        /// <returns></returns>
        public static Tuple<IJobDetail, ITrigger> RestartJob(IScheduler qtzScheduler, ScheduleTask taskOld, ScheduleTask taskNew)
        {
            //作业计划属性发生变更，则从调度器中删除此作业
            JobKey jobKey = GetJobKey(taskOld);
            qtzScheduler.DeleteJob(jobKey); //删除旧的作业

            return JobHelp.CreatScheduleJob(qtzScheduler, taskNew);
        }

        /// <summary>
        /// 使用作业计划来创建作业
        /// </summary>
        /// <param name="qtzScheduler">调度器</param>
        /// <param name="pl">作业计划</param>
        /// <param name="clMethod">作业采集方法</param>
        /// <returns>二元组</returns>
        public static Tuple<IJobDetail, ITrigger> ScheduleJobByPlan(IScheduler qtzScheduler, ScheduleTask task)
        {
            Tuple<IJobDetail, ITrigger> tuple = null;
           
                IJobDetail ij = CreateJobDetail(task );
                ITrigger ig = CreateTrigger(task);
                qtzScheduler.ScheduleJob(ij, ig);
                tuple = new Tuple<IJobDetail, ITrigger>(ij, ig);

            return tuple;
        }
    }
}
